home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / JWrappingLabel.java < prev    next >
Text File  |  1998-09-26  |  11KB  |  395 lines

  1. package com.symantec.itools.swing;
  2.  
  3. import java.awt.Graphics;
  4. import java.awt.FontMetrics;
  5. import java.awt.Dimension;
  6. import java.awt.Label;
  7. import java.beans.PropertyVetoException;
  8. import java.beans.PropertyChangeListener;
  9. import java.beans.VetoableChangeListener;
  10. import java.beans.PropertyChangeEvent;
  11. import com.sun.java.swing.JComponent;
  12. import com.sun.java.swing.SwingConstants;
  13. import com.symantec.itools.beans.VetoableChangeSupport;
  14. import com.symantec.itools.beans.PropertyChangeSupport;
  15.  
  16. /**
  17.  * This class implements a multiple-line text label.
  18.  * It displays text on one or more lines, wrapping text
  19.  * as needed to fit in the available horizontal space.
  20.  */
  21. public class JWrappingLabel
  22.     extends    JComponent
  23.     implements SwingConstants
  24. {
  25.     /**
  26.      * The text string being displayed.
  27.      */
  28.     protected String text = "";
  29.  
  30.     /**
  31.      * The current text alignment.
  32.      * One of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT.
  33.      * @see com.sun.java.swing.SwingConstants#LEFT
  34.      * @see com.sun.java.swing.SwingConstants#CENTER
  35.      * @see com.sun.java.swing.SwingConstants#RIGHT
  36.      */
  37.     protected int align;
  38.  
  39.     /**
  40.      * Constructs a default wrapping label. Default values are an empty text string
  41.      * and left alignment.
  42.      */
  43.     public JWrappingLabel()
  44.     {
  45.         this("");
  46.     }
  47.  
  48.     /**
  49.      * Constructs a wrapping label that displays the specified string.
  50.      * The label will default to left alignment.
  51.      *
  52.      * @param s string to be displayed in label
  53.      */
  54.     public JWrappingLabel(String s)
  55.     {
  56.         this(s, LEFT);
  57.     }
  58.  
  59.     /**
  60.      * Constructs wrapping label with the specified text and alignment.
  61.      *
  62.      * @param s the string to be displayed in label
  63.      * @param a the alignment, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
  64.      *
  65.      * @see com.symantec.itools.swing.Alignment
  66.      * @see com.symantec.itools.swing.Alignment#ALIGN_LEFT
  67.      * @see com.symantec.itools.swing.Alignment#ALIGN_CENTERED
  68.      * @see com.symantec.itools.swing.Alignment#ALIGN_RIGHT
  69.      */
  70.     public JWrappingLabel(String s, int a)
  71.     {
  72.         try
  73.         {
  74.             setText(s);
  75.         }
  76.         catch(PropertyVetoException veto) {};
  77.  
  78.         try
  79.         {
  80.             setTextAlignment(a);
  81.         }
  82.         catch(PropertyVetoException veto) {};
  83.     }
  84.  
  85.  
  86.     //--------------------------------------------------
  87.     // accessor members
  88.     //--------------------------------------------------
  89.  
  90.     /**
  91.      * Gets the current text alignment setting.
  92.      *
  93.      * @return the current alignment, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
  94.      * @see #setTextAlignment
  95.      * @see com.symantec.itools.swing.Alignment
  96.      * @see com.symantec.itools.swing.Alignment#ALIGN_LEFT
  97.      * @see com.symantec.itools.swing.Alignment#ALIGN_CENTERED
  98.      * @see com.symantec.itools.swing.Alignment#ALIGN_RIGHT
  99.      */
  100.     public int getTextAlignment()
  101.     {
  102.         return align;
  103.     }
  104.  
  105.     /**
  106.      * Sets the text alignment.
  107.      *
  108.      * @param newAlignStyle the new alignment style, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
  109.      * @see #getTextAlignment
  110.      * @see com.symantec.itools.swing.Alignment
  111.      * @see com.symantec.itools.swing.Alignment#ALIGN_LEFT
  112.      * @see com.symantec.itools.swing.Alignment#ALIGN_CENTERED
  113.      * @see com.symantec.itools.swing.Alignment#ALIGN_RIGHT
  114.      * @exception PropertyVetoException
  115.      * if the specified property value is unacceptable
  116.      */
  117.     public void setTextAlignment(int newAlignStyle)
  118.         throws PropertyVetoException
  119.     {
  120.         if (align != newAlignStyle)
  121.         {
  122.             Integer oldAlignStyleInt = new Integer(align);
  123.             Integer newAlignStyleInt = new Integer(newAlignStyle);
  124.             
  125.             vetos.fireVetoableChange("textAlignment",oldAlignStyleInt,newAlignStyleInt);
  126.             
  127.             align = newAlignStyle;
  128.             
  129.             changes.firePropertyChange("textAlignment",oldAlignStyleInt,newAlignStyleInt);
  130.             
  131.             repaint();
  132.         }
  133.     }
  134.  
  135.     /**
  136.      * Gets the current label text.
  137.      *
  138.      * @return the label's text string
  139.      * @see #setText
  140.      */
  141.     public String getText()
  142.     {
  143.         return text;
  144.     }
  145.  
  146.     /**
  147.      * Sets the label text.
  148.      *
  149.      * @param s the new label text
  150.      *
  151.      * @see #getText
  152.      * @exception PropertyVetoException
  153.      * if the specified property value is unacceptable
  154.      */
  155.     public void setText(String newText)
  156.         throws PropertyVetoException
  157.     {
  158.         if (!(text.equals(newText)))
  159.         {
  160.             String oldText;
  161.  
  162.             oldText = text;
  163.  
  164.             vetos.fireVetoableChange("text", oldText, newText);
  165.             text = newText;
  166.             changes.firePropertyChange("text", oldText, newText);
  167.             repaint();
  168.         }
  169.     }
  170.  
  171.     //--------------------------------------------------
  172.     // event methods
  173.     //--------------------------------------------------
  174.  
  175.  
  176.     //--------------------------------------------------
  177.     // class methods
  178.     //--------------------------------------------------
  179.  
  180.  
  181.     //--------------------------------------------------
  182.     // member methods
  183.     //--------------------------------------------------
  184.  
  185.     /**
  186.      * Returns an empty string.
  187.      * This is a standard Java AWT method which typically returns a string
  188.      * representing the state of this object.
  189.      *
  190.      * @return the empty string
  191.      */
  192.     public String paramString()
  193.     {
  194.         //???RKM??? Why are we doing this ???
  195.         return "";
  196.     }
  197.     
  198.     /**
  199.      * Paints this component using the given graphics context.
  200.      * This is a standard Java AWT method which typically gets called
  201.      * by the AWT to handle painting this component. It paints this component
  202.      * using the given graphics context. The graphics context clipping region
  203.      * is set to the bounding rectangle of this component and its [0,0]
  204.      * coordinate is this component's top-left corner.
  205.      *
  206.      * @param g the graphics context used for painting
  207.      * @see java.awt.Component#repaint
  208.      * @see java.awt.Component#update
  209.      */
  210.     public void paintComponent(Graphics g)
  211.     {
  212.         if(text != null)
  213.         {
  214.             int x;
  215.             int y;
  216.             int boundx;
  217.             int boundy;
  218.             Dimension d;
  219.             int fromIndex = 0;
  220.             int pos = 0;
  221.             int bestpos;
  222.             String largestString;
  223.             String s;
  224.  
  225.             // Set up some class variables
  226.             FontMetrics fm = getToolkit().getFontMetrics(getFont());
  227.             int baseline = fm.getMaxAscent();
  228.  
  229.             // Get the maximum height and width of the current control
  230.             d = getSize();
  231.             boundx = d.width;
  232.             boundy = d.height;
  233.  
  234.             // X and Y represent the coordinates of the upper left portion
  235.             // of the next text line.
  236.             x = 0;
  237.             y = 0;
  238.  
  239.             // While we haven't passed the bottom of the label and we
  240.             // haven't run past the end of the string...
  241.             while((y + fm.getHeight()) <= boundy && fromIndex != -1)
  242.             {
  243.                 // Automatically skip any spaces at the beginning of the line
  244.                 while(fromIndex < text.length() && text.charAt(fromIndex) == ' ')
  245.                 {
  246.                     ++fromIndex;
  247.                     // If we hit the end of line while skipping spaces, we're done.
  248.                     if (fromIndex >= text.length()) break;
  249.                 }
  250.  
  251.                 // fromIndex represents the beginning of the line
  252.                 pos = fromIndex;
  253.                 bestpos = -1;
  254.                 largestString = null;
  255.  
  256.                 while(pos >= fromIndex)
  257.                 {
  258.                     pos = text.indexOf(' ', pos);
  259.  
  260.                     // Couldn't find another space?
  261.                     if(pos == -1)
  262.                     {
  263.                         s = text.substring(fromIndex);
  264.                     }
  265.                     else
  266.                     {
  267.                         s = text.substring(fromIndex, pos);
  268.                     }
  269.  
  270.                     // If the string fits, keep track of it.
  271.                     if (fm.stringWidth(s) < boundx)
  272.                     {
  273.                         largestString = s;
  274.                         bestpos = pos;
  275.  
  276.                         // If we've hit the end of the string, use it.
  277.                         if (pos == -1) break;
  278.                     }
  279.                     else
  280.                     {
  281.                         break;
  282.                     }
  283.  
  284.                     ++pos;
  285.                 }
  286.  
  287.                 if(largestString == null)
  288.                 {
  289.                     //???RKM??? We should not do this - we can do it right
  290.                     
  291.                     // Couldn't wrap at a space, so find the largest line
  292.                     // that fits and print that.  Note that this will be
  293.                     // slightly off -- the width of a string will not necessarily
  294.                     // be the sum of the width of its characters, due to kerning.
  295.                     int totalWidth = 0;
  296.                     int oneCharWidth = 0;
  297.  
  298.                     pos = fromIndex;
  299.  
  300.                     while (pos < text.length())
  301.                     {
  302.                         oneCharWidth = fm.charWidth(text.charAt(pos));
  303.                         if ((totalWidth + oneCharWidth) >= boundx) break;
  304.                         totalWidth += oneCharWidth;
  305.                         ++pos;
  306.                     }
  307.  
  308.                     drawAlignedString(g, fm, baseline, text.substring(fromIndex, pos), x, y, boundx);
  309.                     fromIndex = pos;
  310.                 }
  311.                 else
  312.                 {
  313.                     drawAlignedString(g, fm, baseline, largestString, x, y, boundx);
  314.  
  315.                     fromIndex = bestpos;
  316.                 }
  317.  
  318.                 y += fm.getHeight();
  319.             }
  320.  
  321.             // We're done with the font metrics...
  322.             fm = null;
  323.         }
  324.     }
  325.  
  326.     /**
  327.      * Adds a listener for all event changes.
  328.      * @param PropertyChangeListener listener the listener to add.
  329.      * @see #removePropertyChangeListener
  330.      */
  331.     public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
  332.     {
  333.         changes.addPropertyChangeListener(listener);
  334.     }
  335.  
  336.     /**
  337.      * Removes a listener for all event changes.
  338.      * @param PropertyChangeListener listener the listener to remove.
  339.      * @see #addPropertyChangeListener
  340.      */
  341.     public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
  342.     {
  343.         changes.removePropertyChangeListener(listener);
  344.     }
  345.  
  346.     /**
  347.      * Adds a vetoable listener for all event changes.
  348.      * @param VetoableChangeListener listener the listener to add.
  349.      * @see #removeVetoableChangeListener
  350.      */
  351.     public synchronized void addVetoableChangeListener(VetoableChangeListener listener)
  352.     {
  353.         vetos.addVetoableChangeListener(listener);
  354.     }
  355.  
  356.     /**
  357.      * Removes a vetoable listener for all event changes.
  358.      * @param VetoableChangeListener listener the listener to remove.
  359.      * @see #addVetoableChangeListener
  360.      */
  361.     public synchronized void removeVetoableChangeListener(VetoableChangeListener listener)
  362.     {
  363.         vetos.removeVetoableChangeListener(listener);
  364.     }
  365.  
  366.     /**
  367.      * This helper method draws a string aligned the requested way.
  368.      * @param g the graphics context used for painting
  369.      * @param s the string to draw
  370.      * @param x the point to start drawing from, x coordinate
  371.      * @param y the point to start drawing from, y coordinate
  372.      * @param width the width of the area to draw in, in pixels
  373.      */
  374.     protected void drawAlignedString(Graphics g, FontMetrics fm, int baseline, String s, int x, int y, int width)
  375.     {
  376.         int drawx = x;
  377.         int drawy = y + baseline;
  378.         
  379.         if (align != LEFT)
  380.         {
  381.             int sw = fm.stringWidth(s);
  382.             
  383.             if (align == CENTER)
  384.                 drawx += (width - sw) / 2;
  385.             else if (align == RIGHT)
  386.                 drawx = drawx + width - sw;
  387.         }
  388.  
  389.         g.drawString(s, drawx, drawy);
  390.     }
  391.     
  392.     private VetoableChangeSupport vetos = new VetoableChangeSupport(this);
  393.     private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  394. }
  395.